package luj.game.robot.internal.net.http.collect;

import luj.game.robot.api.network.http.RobotHttpHandler;
import luj.game.robot.api.network.http.RobotHttpMeta;
import luj.game.robot.api.network.http.RobotHttpModule;
import luj.game.robot.internal.dynamic.combine.AllBeanCombiner;

import java.util.List;
import java.util.Map;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.stream.Collectors.toMap;

public class HandleMapMaker {

  public HandleMapMaker(AllBeanCombiner.Result rootBean) {
    _rootBean = rootBean;
  }

  public HandleMap make() {
    AllBeanCombiner.Http http = _rootBean.http();
    Map<String, RobotHttpHandler> instMap = toNameMap(http.handler());
    Map<String, RobotHttpModule> moduleMap = toNameMap(http.module());

    List<HandleMap.Handler> handleList = http.meta().stream()
        .<HandleMap.Handler>map(m -> createHandler(m, instMap, moduleMap))
        .toList();

    for (HandleMap.Handler h : handleList) {
      var handler = (MHandlerImpl) h;
      handler._uri = new UriResolver(handler).resolve();
    }

    var map = new MapImpl();
    map._handleMap = handleList.stream()
        .collect(toMap(HandleMap.Handler::getUri, h -> h));

    return map;
  }

  private <T> Map<String, T> toNameMap(List<T> list) {
    return list.stream()
        .collect(toMap(e -> e.getClass().getName(), h -> h));
  }

  private MHandlerImpl createHandler(RobotHttpMeta meta, Map<String, RobotHttpHandler> instMap, Map<String, RobotHttpModule> moduleMap) {
    Class<?> metaType = meta.getClass();
    String metaName = metaType.getName();

    Class<?> handlerType = metaType.getEnclosingClass();
    checkNotNull(handlerType, metaName);

    RobotHttpHandler handlerInst = instMap.get(handlerType.getName());
    checkNotNull(handlerInst, metaName);

    RobotHttpModule module = moduleMap.get(meta.module().getName());
    checkNotNull(module, metaName);

    var handler = new MHandlerImpl();
    handler._handler = handlerInst;
    handler._meta = meta;
    handler._module = module;

    return handler;
  }

  private final AllBeanCombiner.Result _rootBean;
}
